/* eslint-disable unicorn/prefer-spread */
import { Effect, SynchronizedRef } from "effect";

// 模拟获取用户年龄的异步 API
const getUserAge = (userId: number) =>
  // 返回 userId * 10 作为年龄
  // 使用 Effect.delay 模拟网络延迟，延迟时间与用户ID成反比
  Effect.succeed(userId * 10).pipe(Effect.delay(10 - userId));

const meanAge = Effect.gen(function* () {
  // 创建初始为空的数组 SynchronizedRef
  const ref = yield* SynchronizedRef.make<number[]>([]);

  // 在执行效果前记录当前状态 SynchronizedRef.get
  // 帮助理解并发执行时的状态变化
  const log = <R, E, A>(label: string, effect: Effect.Effect<A, E, R>) =>
    Effect.gen(function* () {
      const value = yield* SynchronizedRef.get(ref);
      yield* Effect.log(label, value);
      return yield* effect;
    });
  // 每个任务：获取用户年龄并添加到共享数组中
  // 使用 SynchronizedRef.updateEffect 更新共享状态
  const task = (id: number) =>
    log(
      `task ${id}`,
      SynchronizedRef.updateEffect(ref, (sumOfAges) =>
        Effect.gen(function* () {
          const age = yield* getUserAge(id);
          return sumOfAges.concat(age);
        }),
      ),
    );

  // 同时运行4个任务，但限制并发数为2
  // 确保线程安全的并发访问
  yield* Effect.all([task(1), task(2), task(3), task(4)], {
    concurrency: 2,
  });

  // Retrieve the updated value
  const value = yield* SynchronizedRef.get(ref);
  return value;
});

Effect.runPromise(meanAge).then(Effect.log);
/*
Output:
timestamp=... level=INFO fiber=#2 message="task 1" message=[]
timestamp=... level=INFO fiber=#3 message="task 2" message=[]
timestamp=... level=INFO fiber=#2 message="task 3" message="[
  10
]"
timestamp=... level=INFO fiber=#3 message="task 4" message="[
  10,
  20
]"
[ 10, 20, 30, 40 ]
*/
